<?php

namespace common\service;


use common\exception\LogicException;
use common\model\EntityModel;
use common\model\TaskModel;
use common\model\TaskWorkOrderModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Exception;
use think\Hook;
use Throwable;
use Webman\Stomp\Client;

class EntityAbolitionOrEnableService
{
    use SingletonTrait;

    /**
     * 实体废除和启用
     * @param $status
     * @param $param
     * @return bool
     * @throws Throwable
     */
    public function entityAbolitionOrEnabling($status, $param)
    {
        // 查询是否是分镜
        $entityData = model(EntityModel::class)->where(['id' => $param['id']])->find();

        //判定该实体是分镜还是概念
        if (empty($entityData) || !in_array(module_by_id($entityData['module_id'])['code'], ['storyboard', 'design'])) {
            throw new LogicException('An operation has been cancelled or data does not exist', ErrorCode::GET_ENTITY_DATA_FAIL);
        }

        $entityData['json'] = json_decode($entityData['json'] ?? '{}', true);
        // 废除
        if ($status == 'Abo') {
            // 处理废除任务
            $changeEntity = $this->entityExecAbo($entityData);
        } else {
            // 处理启用状态
            $changeEntity = $this->entityExecEna($entityData);
        }

        if ($changeEntity) {
            // 已迁移
            $eventData = [
                'entity_id' => $param['id'],
                'operate' => $status,
                'operate_at' => time(),
                'operator' => request()->getUserId(),
            ];
//            Hook::listen('entity_closed_operate', $eventData);
            Client::send("entity_close_operate_async_send_producer_message", build_queue_data_with_xu($eventData));
            // 创建 && 发送聊天
            EntityService::getInstance()->entityAbolitionOrEnablingSendMessage($changeEntity, $status);
            //同步产需统计
            Client::send('sync_demand_pool_report', build_queue_data_with_xu([
                'project_id' => $entityData['project_id'],
                'initial_episode_code' => $entityData['initial_episode_code'],
            ]));
        }
        return $changeEntity;
    }


    /**
     * 实体废除
     * @param $entity
     * @return false|mixed
     * @throws Exception
     * @throws Throwable
     */
    public function entityExecAbo($entity)
    {
        $moduleCode = module_by_id($entity['module_id'])['code'];
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        //判定该资产是否已经废除过了
        if (isset($entity['json'][$moduleCode . '_status']) && $entity['json'][$moduleCode . '_status'] == $closedStatus['id']) {
            return false;
        }

        $taskAbolitionService = TaskAbolitionService::getInstance();
        //判定是概念还是分镜
        $texTodoTaskList = [];
        if ($moduleCode == 'design') {
            $statusMerged = StatusService::getInstance()->entityStatusList('design', '');
            $statusMerged = array_column($statusMerged, 'code_list', 'code');

            $publishedStatusCodeList = [];
            foreach ($statusMerged as $mergeCode => $mergeCodeList) {
                if (in_array($mergeCode, ['not_started', 'inprogress', 'final'])) {
                    $publishedStatusCodeList = array_merge($publishedStatusCodeList, $mergeCodeList);
                }
            }

            // 判断是否二次补充完毕,清单发布状态
            if (empty($entity['json']['design_status'])) {
                throw new LogicException('Repeal failed, design status is null', ErrorCode::TASK_ABO_UPDATE_DESIGN_FAIL);
            }

            // 查询贴图待办任务
            $texTodoTaskList = $taskAbolitionService->getEntityTexTodoTask($entity);
        }

        $childrenEntity = EntityService::getInstance()->getDownstreamEntity($entity);
        //镜头或资产的实体 ,包含自己进去
        $entityIds = [$entity['id']];
        if (!empty($childrenEntity)) {
            $entityIds[] = $childrenEntity['id'];
        }
        // 查询出外包的实体
        $entityOutsideList = EntityService::getInstance()->getOutsourceEntity($entity);
        if (!empty($entityOutsideList)) {
            $entityIds = array_merge($entityIds, array_column($entityOutsideList, 'id'));
        }
        if (!empty($childrenEntity)) {
            $childrenEntityOutsideList = EntityService::getInstance()->getOutsourceEntity($childrenEntity);
            if (!empty($childrenEntityOutsideList)) {
                $entityIds = array_merge($entityIds, array_column($childrenEntityOutsideList, 'id'));
            }
        }

        //判定是否有制作过的任务
        $taskIsMaking = $taskAbolitionService->getTaskStatus($entity['project_id'], $entityIds, $taskList);

        $taskModel = model(TaskModel::class);
        $taskModel->startTrans();
        // 任务已开始,修改任务状态
        try {
            // 处理审批中的任务
            $taskAbolitionService->execSubmitted($taskList);

            if ($taskIsMaking) {
                // 修改状态
                $this->setEntityAndChildrenStatus('closed', $entityIds);
                $taskAbolitionService->setTaskStatus('closed', $taskList);
                // 发送工单会话消息
                $taskAbolitionService->pushWorkOrderChatMessage($taskList, TaskWorkOrderModel::STATUS_EXPIRED);
                // 更改工单状态
                $taskAbolitionService->setTaskWorkStatus($taskList, TaskWorkOrderModel::STATUS_EXPIRED);
                // 弃用待办任务
                $taskAbolitionService->setTaskStatus('closed', $texTodoTaskList);
            } else {
                // 删除清单,删除任务
                $taskAbolitionService->removeEntity($entityIds);
                $taskAbolitionService->removeTask($taskList);
                // 解除工单会话群
                $taskAbolitionService->batchDisbandChat($taskList);
                // 删除待办任务
                $taskAbolitionService->removeTask($texTodoTaskList);
            }

            // 删除实体与剧集的关联关系
            EntityEpisodeRelationService::getInstance()->relationDelete(['entity_id' => ['IN', $entityIds]]);
            //删除掉剧本拆分的清单
            if ($moduleCode == 'design') {
                // 取消关联关系 关卡不需要处理
                $this->cancelDesignRelateLevel($entity['name'], $entity['project_id'], $childrenEntity['id'] ?? null, $entity['json']);
            }
            $taskModel->commit();
        } catch (Throwable $e) {
            $taskModel->rollback();
            throw $e;
        }
        return $entity;

    }

    /**
     * 更改清单状态
     * @param $status
     * @param $entityId
     * @return bool
     * @throws Exception
     */
    public function setEntityAndChildrenStatus($status, $entityId)
    {
        // 组织编辑数据
        if (empty($entityId)) {
            return false;
        }

        $updData = [];
        // 更改的状态
        $taskStatus = StatusService::getInstance()->getOne(['code' => $status], 'id')['id'] ?? '';
        $oldEntityData = model(EntityModel::class)->where(['id' => ['IN', $entityId]])->field('id,json,module_id')->select();
        foreach ($oldEntityData as $val) {
            $json = json_decode($val['json'], true);
            // 废除功能,旧数据
            $prefix = module_by_id($val['module_id'])['code'];
            $field = $prefix . '_deprecate_data';
            if (empty($json[$field])) {
                $json[$field] = $json;
            }
            // 镜头状态
            $json[$prefix . '_status'] = $taskStatus;
            $updData[] = [
                'id' => $val['id'],
                'json' => $json,
            ];
        }

        // 批量更新数据
        if (empty($updData)) {
            return true;
        }
        CommonService::instance('entity')->commonBatchUpdate($updData);
        return true;

    }

    /**
     * 取消关联与被关联
     * @param $name
     * @param $projectId
     * @param $childrenEntityId
     * @param $json
     * @return void
     * @throws Exception
     */
    public function cancelDesignRelateLevel($name, $projectId, $childrenEntityId, $json)
    {
        // 删除关卡或者场景后自动解除对应关联关系
        // 如果该概念为 不为关卡  可通过 design_relate_level 来解除掉 level_relate_asset 以及 level_asset  以及 shot_asset
        // 如果该概念为 为关卡 可通过 level_relate_asset  来解除掉 design_relate_level 以及 shot_level

        $data = [];
        if ($json['design_category'] == '关卡') {
            // 通过关卡找到资产
            $assetNameList = array_filter(explode(",", $json['level_relate_asset'] ?? ""));
            if (!empty($assetNameList)) {
                //找到资产概念
                $assetList = model(EntityModel::class)->where([
                    'project_id' => $projectId,
                    'module_id' => module_by_code("design")['id'],
                    'name' => ["IN", $assetNameList],
                ])->select();

                //过滤概念资产中的关卡
                $this->filterJsonRelationEntity($assetList, 'design_relate_level', $name, $data);
            }
            //找到镜头
            if (!empty($childrenEntityId)) {
                $shotList = model(EntityModel::class)->where([
                    'project_id' => $projectId,
                    'module_id' => module_by_code("shot")['id'],
                    "_string" => "FIND_IN_SET('{$childrenEntityId}', JSON_UNQUOTE(JSON_EXTRACT(json, '$.shot_level')))"
                ])->select();
                //过滤掉镜头中的关卡
                $this->filterJsonRelationEntity($shotList, 'shot_level', $childrenEntityId, $data);
            }
        } else {
            // 通过概念找到关卡
            $levelNameList = array_filter(explode(",", $json['design_relate_level'] ?? ""));
            if (!empty($levelNameList)) {
                //找到资产概念
                $levelList = model(EntityModel::class)->where([
                    'project_id' => $projectId,
                    'module_id' => module_by_code("design")['id'],
                    'name' => ["IN", $levelNameList],
                ])->select();

                //过滤掉关卡概念中的资产
                $this->filterJsonRelationEntity($levelList, 'level_relate_asset', $name, $data);
            }

            if (!empty($childrenEntityId)) {
                $assetList = model(EntityModel::class)->where([
                    'project_id' => $projectId,
                    'module_id' => module_by_code("level")['id'],
                    "_string" => "FIND_IN_SET('{$childrenEntityId}', JSON_UNQUOTE(JSON_EXTRACT(json, '$.level_asset')))"
                ])->select();

                //过滤掉关卡中的资产
                $this->filterJsonRelationEntity($assetList, 'level_asset', $childrenEntityId, $data);

                $shotList = model(EntityModel::class)->where([
                    'project_id' => $projectId,
                    'module_id' => module_by_code("shot")['id'],
                    "_string" => "FIND_IN_SET('{$childrenEntityId}', JSON_UNQUOTE(JSON_EXTRACT(json, '$.shot_asset')))"
                ])->select();

                //过滤掉镜头中的资产
                $this->filterJsonRelationEntity($shotList, 'shot_asset', $childrenEntityId, $data);
            }
        }


        if (!empty($data)) {
            request()->moduleCode = 'entity';
            CommonService::instance('entity')->commonBatchUpdate($data, null, false);
            request()->getModuleCode('design');
        }
    }

    /**
     * 实体启用
     * @param $entity
     * @return false|void
     * @throws Exception
     */
    public function entityExecEna($entity)
    {
        $moduleCode = module_by_id($entity['module_id'])['code'];
        $closedStatus = StatusService::getInstance()->getTaskDefaultClosedStatus();
        if (isset($entity['json'][$moduleCode . '_status']) && $entity['json'][$moduleCode . '_status'] != $closedStatus['id']) {
            // 当前不是废除状态不需要处理
            return false;
        }
        $childrenEntity = EntityService::getInstance()->getDownstreamEntity($entity);
        if (empty($childrenEntity)) {
            throw new LogicException('entity id error', ErrorCode::GET_ENTITY_STATUS_ID_ERROR);
        }
        $childrenEntity['json'] = json_decode($childrenEntity['json'], true);

        $childrenEntity = [$childrenEntity, $entity];
        $entityId = array_column($childrenEntity, 'id');
        $taskList = model(TaskModel::class)
            ->field('id,json')
            ->where(['project_id' => $entity['project_id'], 'entity_id' => ['IN', $entityId]])
            ->select();

        //重新启用时,外包可以继续正常做任务
        $taskIdList = array_column($taskList, 'id');
        $orderTaskList = OrderService::getInstance()->getOrderTaskListByTaskIdList($taskIdList);
        $partyBTaskList = [];
        $partyBEntityList = [];
        if (!empty($orderTaskList)) {
            $partyBTaskIds = array_column($orderTaskList, 'real_task_id');
            $partyBTaskList = model(TaskModel::class)->where(['id' => ["IN", $partyBTaskIds]])->field("id,entity_id,json")->select();
            $partyBEntityIds = array_column($partyBTaskList, 'entity_id');
            $partyBEntityList = model(EntityModel::class)->where(['id' => ["IN", $partyBEntityIds]])->select();
            $partyBEntityList = array_map(function ($partyBEntityItem) {
                $partyBEntityItem['json'] = json_decode($partyBEntityItem['json'] ?? '{}', true);
                return $partyBEntityItem;
            }, $partyBEntityList);
        }

        //融合外包和当前任务
        $taskList = array_merge($taskList, $partyBTaskList);
        $childrenEntity = array_merge($childrenEntity, $partyBEntityList);

        // 恢复清单状态
        ShotEnableService::getInstance()->updateEntityJson($childrenEntity);
        // 恢复任务状态
        if (!empty($taskList)) {
            TaskEnableService::getInstance()->recoveryTask($taskList);
        }

        return $entity;
    }


    /**
     * 获取子级实体数据
     * @param $entity
     * @return array|false|mixed|string
     */
    public function getChildrenEntityData($entity)
    {
        $moduleCode = module_by_id($entity['module_id'])['code'];
        $where = [
            'project_id' => $entity['project_id'],
        ];
        if ($moduleCode == 'design') {
            $assetId = module_by_code('asset')['id'];
            $levelId = module_by_code('level')['id'];
            $where['module_id'] = ["IN", [$assetId, $levelId]];
            $where["json_extract(json, concat('$.', CASE module_id WHEN {$assetId} THEN 'asset' WHEN {$levelId} THEN 'level' END , '_design'))"] = $entity['id'];
        } else {
            $where['module_id'] = module_by_code('shot')['id'];
            $where["json_extract(json, '$.shot_storyboard')"] = $entity['id'];
        }
        //如果子级找不到不能启用

        $currentEntity = model(EntityModel::class)->where($where)
            ->field('id,project_id,json,module_id')
            ->find();

        $currentEntity['json'] = json_decode($currentEntity['json'] ?? '{}', true);
        return $currentEntity;
    }

    /**
     * 过滤json中的关联实体
     * @return void
     */
    public function filterJsonRelationEntity($entityList, $relationName, $value, &$data)
    {
        //找到资产概念
        foreach ($entityList as $entityItem) {
            $newJson = $jsonArr = json_decode($entityItem['json'], true);
            if (empty($jsonArr[$relationName])) {
                continue;
            }
            //过滤掉概念中的关卡
            $has = false;
            $relateList = array_filter(explode(",", $jsonArr[$relationName]));
            foreach ($relateList as $relateIndex => $relateItem) {
                if ($relateItem == $value) {
                    unset($relateList[$relateIndex]);
                    $has = true;
                }
            }
            //如果没有更新,不记录
            if (!$has) {
                continue;
            }
            $newJson[$relationName] = join(",", $relateList);
            $data[$entityItem['id']] = [
                'id' => $entityItem['id'],
                'json' => $newJson
            ];
        }
    }
}
